Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Linq
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Windows.Forms
Imports C4F.DevKit.Calendar.Components

Namespace C4F.DevKit.Calendar.Controls
	''' <summary>
	''' This control is used to configure an appointments with specific details to be stored.
	''' </summary>
	<ToolboxItem(True), ToolboxBitmap(GetType(AppointmentDetails))> _
	Public Partial Class AppointmentDetails
		Inherits UserControl
		#Region "Enums"

		''' <summary>
		''' A type which specifies a time interval for the time combo boxes in this control
		''' </summary>
		Public Enum TimeIntervalType
			''' <summary>
			''' Indicates that there is no specified time interval
			''' </summary>
			NotSet = 0

			''' <summary>
			''' An interval of ten minutes
			''' </summary>
			Ten = 1

			''' <summary>
			''' An interval of fifteen minutes
			''' </summary>
			Fifteen = 2

			''' <summary>
			''' An interval of thirty minutes
			''' </summary>
			Thirty = 3

			''' <summary>
			''' An interval of sixty minutes
			''' </summary>
			Sixty = 4
		End Enum

		#End Region ' Enums

		#Region "Private Data"

		Private _appt As Appointment

		Private Const DEFAULT_TIME_INTERVAL_IN_MINS As Integer = 30
		Private _weekdayButtons As CheckBox()
		Private _calendarService As CalendarService
		Private _timeInterval As TimeIntervalType
		Private _includeWindowsContactsAsAttendees As Boolean = True
		Private _attendees As List(Of Attendee) = New List(Of Attendee)()
		Private Const DESIGNER_CATEGORY As String = "Calendar"

		#End Region ' Private Data

		#Region "Properties"

		''' <summary>
		''' The appointment being displayed in the control.
		''' </summary>
		<Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
		Public Property Appointment() As Appointment
			Get
				PopulateAppointment()
				Return _appt
			End Get

			Set(ByVal value As Appointment)
				_appt = value
				PopulateControls()
			End Set
		End Property

		''' <summary>
		''' The interval between times in the dropdown boxes for the start and end times.
		''' </summary>
		<Browsable(True), Category(DESIGNER_CATEGORY), Description("The interval populated in the start/end times dropdowns."), DefaultValue(TimeIntervalType.Fifteen)> _
		Public Property TimeInterval() As TimeIntervalType
			Get
				Return _timeInterval
			End Get
			Set(ByVal value As TimeIntervalType)
				_timeInterval = value
			End Set
		End Property

		''' <summary>
		''' The CalendarService to use with this control and its appointment.
		''' </summary>
		<Browsable(True), Category(DESIGNER_CATEGORY)> _
		Public Property CalendarService() As CalendarService
			Get
				Return _calendarService
			End Get
			Set(ByVal value As CalendarService)
				If Not value Is Nothing Then
					_calendarService = value
				End If
			End Set
		End Property

		''' <summary>
		''' Determines if the user's windows contacts should be included when choosing attendees.
		''' </summary>
		''' <remarks>The Contacts will only be shown if the CalendarService property is set.</remarks>
		<Browsable(True), DefaultValue(True), Description("Determines if the user's windows contacts should be included when choosing attendees. The Contacts will only be shown if the CalendarService property is set.")> _
		Public Property ShowWinContactsAsAttendees() As Boolean
			Get
				Return _includeWindowsContactsAsAttendees
			End Get
			Set(ByVal value As Boolean)
				_includeWindowsContactsAsAttendees = value
			End Set
		End Property

		''' <summary>
		''' The list that the user will pick from in order to add attendees to the appointment.
		''' </summary>
		''' <remarks>This is not the attendees that will be added to the actual appointment.</remarks>
		<Browsable(False), Category(DESIGNER_CATEGORY), Description("The list that the user will pick from in order to add attendees to the appointment.")> _
		Public ReadOnly Property AttendeesList() As List(Of Attendee)
			Get
				If _attendees Is Nothing Then
					_attendees = New List(Of Attendee)()
				End If

				Return _attendees
			End Get
		End Property

		#End Region ' Properties

		#Region "Constructor"

		''' <summary>
		''' Creates a new AppointmentDetails control.
		''' </summary>
		Public Sub New()
			InitializeComponent()

			If (Not DesignMode) Then
				InitializeProperties()
				PopulateTimes()
				SetDateTimes()
				_appt = New Appointment()
			End If

			_weekdayButtons = New CheckBox() {chkSunday, chkMonday, chkTuesday, chkWednesday, chkThursday, chkFriday, chkSaturday}


		End Sub

		#End Region ' Constructor

		#Region "Methods"

		#Region "Event Handlers"

		Private Sub chkAllDay_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) Handles chkAllDay.CheckedChanged
			OnCheckAllDay()
		End Sub

		Private Sub rdoWeekly_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) Handles rdoWeekly.CheckedChanged
			For Each weekdayButton As CheckBox In _weekdayButtons
				weekdayButton.Enabled = rdoWeekly.Checked
				weekdayButton.Checked = False
			Next weekdayButton

			If rdoWeekly.Checked Then
				Dim startWeekday As Integer = CInt(Fix(dtStartDate.Value.DayOfWeek))
				_weekdayButtons(startWeekday).Checked = True
			End If
		End Sub

		Private Sub rdoNone_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs) Handles rdoNone.CheckedChanged
			Dim recurrenceControls As Control() = New Control() {rdoNoEndDate, rdoRecurCount, rdoRecurEndDate, txtRecurCount, dtRecurEndDate}

			For Each recControl As Control In recurrenceControls
				recControl.Enabled = Not rdoNone.Checked
			Next recControl
		End Sub

		Private Sub btnAttendees_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAttendees.Click
			PopulateAttendeesWithWinContacts()

			Using form As SelectAttendees = New SelectAttendees(AttendeesList, txtAttendees.Text)
				If form.ShowDialog() = DialogResult.OK Then
					Me.txtAttendees.Text = form.SelectedAttendees
				End If
			End Using
		End Sub

		#End Region ' Event Handlers

		#Region "Private"

		Private Sub OnCheckAllDay()
			cboEndTime.Enabled = Not chkAllDay.Checked
			cboStartTime.Enabled = cboEndTime.Enabled
		End Sub

		Private Sub InitializeProperties()
			TimeInterval = TimeIntervalType.Thirty
		End Sub

		Private Function ValidateTimeFormat() As Boolean
			Dim timeRegex As Regex = New Regex("\d?\d:\d\d (am|pm)", RegexOptions.IgnoreCase)
			Return timeRegex.Match(cboStartTime.Text).Success AndAlso timeRegex.Match(cboEndTime.Text).Success
		End Function

		Private Function ValidateCountFormat() As Boolean
			Return Regex.Match(txtRecurCount.Text, "\d+").Success
		End Function

		Private Sub PopulateAppointment()
			_appt.Attendees = ParseAttendees()

			Dim localZone As TimeZone = TimeZone.CurrentTimeZone
			_appt.StartDateTime = localZone.ToUniversalTime(DateTime.Parse(String.Format("{0} {1}", dtStartDate.Value.ToShortDateString(), cboStartTime.Text)))
			_appt.EndDateTime = localZone.ToUniversalTime(DateTime.Parse(String.Format("{0} {1}", dtEndDate.Value.ToShortDateString(), cboEndTime.Text)))
			_appt.IsAllDayEvent = chkAllDay.Checked
			_appt.Location = txtLocation.Text
			_appt.Notes = txtNotes.Text.Replace(Constants.vbCr, "")
			Console.WriteLine(txtNotes.Text)
			_appt.Summary = txtSubject.Text

			If (Not rdoNone.Checked) Then
				If rdoDaily.Checked Then
					_appt.SetDailyRecurrence()
				ElseIf rdoWeekly.Checked Then
					Dim weekdays As List(Of Weekday) = New List(Of Weekday)()

					For i As Integer = 0 To _weekdayButtons.Length - 1
						If _weekdayButtons(i).Checked Then
							weekdays.Add(CType(i, Weekday))
						End If
					Next i

					_appt.SetWeeklyRecurrence(weekdays)
				ElseIf rdoMonthly.Checked Then
					_appt.SetMonthlyRecurrence()
				ElseIf rdoYearly.Checked Then
					_appt.SetYearlyRecurrence()
				End If

				If rdoRecurCount.Checked Then
					_appt.RecurrenceRule.Count = Int32.Parse(txtRecurCount.Text)
				ElseIf rdoRecurEndDate.Checked Then
					_appt.RecurrenceRule.EndDateTime = localZone.ToUniversalTime(dtRecurEndDate.Value)
				End If
			End If
		End Sub

		Private Sub PopulateTimes()
			Dim [date] As DateTime = DateTime.Today
			Dim interval As Integer = TimeIntervalInMinutes()
			Dim currentDateTime As DateTime = [date]

			Do While currentDateTime.Date = [date]
				cboStartTime.Items.Add(currentDateTime.ToShortTimeString())
				cboEndTime.Items.Add(currentDateTime.ToShortTimeString())

				currentDateTime = currentDateTime.AddMinutes(interval)
			Loop
		End Sub

		Private Function TimeIntervalInMinutes() As Integer
			Select Case TimeInterval
				Case TimeIntervalType.Ten
					Return 10
				Case TimeIntervalType.Fifteen
					Return 15
				Case TimeIntervalType.Thirty
					Return 30
				Case TimeIntervalType.Sixty
					Return 60
				Case Else
					Return DEFAULT_TIME_INTERVAL_IN_MINS
			End Select
		End Function

		Private Sub PopulateControls()
			'Populate Summary section
			Dim attendeeStrings As List(Of String) = New List(Of String)()

			For Each attendee As Attendee In _appt.Attendees
				Dim attendeeString As String = attendee.Name

				If (Not String.IsNullOrEmpty(attendee.EmailAddress)) Then
					attendeeString &= " <" & attendee.EmailAddress & ">"
				End If

				attendeeStrings.Add(attendeeString)
			Next attendee

			txtAttendees.Text = String.Join("; ", attendeeStrings.ToArray())
			txtSubject.Text = _appt.Summary
			txtLocation.Text = _appt.Location

			If Not _appt.Notes Is Nothing Then
				txtNotes.Text = _appt.Notes.Replace(Constants.vbLf, Constants.vbCrLf)
			End If

			' populate Date/Time section
			chkAllDay.Checked = _appt.IsAllDayEvent
			Dim localZone As TimeZone = TimeZone.CurrentTimeZone
			Dim localStart As DateTime = localZone.ToLocalTime(_appt.StartDateTime)
			Dim localEnd As DateTime = localZone.ToLocalTime(_appt.EndDateTime)
			dtStartDate.Value = localStart.Date
			dtEndDate.Value = localEnd.Date
			SetComboBoxText(cboStartTime, localStart.ToShortTimeString())
			SetComboBoxText(cboEndTime, localEnd.ToShortTimeString())

			'Populate Recurrence section
			Dim recRule As RecurrenceRule = _appt.RecurrenceRule

			If recRule Is Nothing Then
				rdoNone.Checked = True
				Return
			End If


			If recRule.EndDateTime = New DateTime() Then
				If recRule.Count = 0 Then
					rdoNoEndDate.Checked = True
				Else
					rdoRecurCount.Checked = True
					txtRecurCount.Text = recRule.Count.ToString()
				End If
			Else
				rdoRecurEndDate.Checked = True
				dtRecurEndDate.Value = localZone.ToLocalTime(recRule.EndDateTime)
			End If

			Select Case recRule.Frequency
				Case Frequency.Daily
					rdoDaily.Checked = True
				Case Frequency.Weekly
					rdoWeekly.Checked = True
					PopulateWeekdays()
				Case Frequency.Monthly
					rdoMonthly.Checked = True
				Case Frequency.Yearly
					rdoYearly.Checked = True
				Case Else
					rdoOther.Checked = True
			End Select
		End Sub

		Private Sub PopulateWeekdays()
			If _appt.RecurOnSunday Then
				chkSunday.Checked = True
			End If

			If _appt.RecurOnMonday Then
				chkMonday.Checked = True
			End If

			If _appt.RecurOnTuesday Then
				chkTuesday.Checked = True
			End If

			If _appt.RecurOnWednesday Then
				chkWednesday.Checked = True
			End If

			If _appt.RecurOnThursday Then
				chkThursday.Checked = True
			End If

			If _appt.RecurOnFriday Then
				chkFriday.Checked = True
			End If

			If _appt.RecurOnSaturday Then
				chkSaturday.Checked = True
			End If
		End Sub

		Private Sub SetComboBoxText(ByVal comboBox As ComboBox, ByVal text As String)
			If (Not comboBox.Items.Contains(text)) Then
				comboBox.Items.Add(text)
			End If

			comboBox.Text = text
		End Sub

		Private Sub SetDateTimes()
			Dim startDateTime As DateTime = DateTime.Now
			Dim newTime As TimeSpan = RoundUpTime(startDateTime.TimeOfDay)
			Console.WriteLine("timespan: " & newTime.ToString())
			Console.WriteLine("old start time: " & startDateTime.ToString())
			startDateTime = startDateTime.Subtract(startDateTime.TimeOfDay)
			startDateTime = startDateTime.Add(newTime)
			Dim endDateTime As DateTime = startDateTime.AddHours(1)

			dtStartDate.Value = startDateTime.Date
			dtEndDate.Value = endDateTime.Date
			SetComboBoxText(cboStartTime, startDateTime.ToShortTimeString())
			SetComboBoxText(cboEndTime, endDateTime.ToShortTimeString())
		End Sub

		Private Function RoundUpTime(ByVal time As TimeSpan) As TimeSpan
			Dim interval As Integer = TimeIntervalInMinutes()
			Dim minuteRemainder As Integer = time.Minutes Mod interval
			'Console.WriteLine("minute rem: " + minuteRemainder

			If minuteRemainder = 0 Then
				Return time
			End If

			Return New TimeSpan(time.Hours, time.Minutes + interval - minuteRemainder, 0)
		End Function

		Private Function ParseAttendees() As List(Of Attendee)
			Dim attendeeStrings As String() = txtAttendees.Text.Split(";"c)

			' one non-whitespace character, optionally followed by any sequence of characters
			' ending with non-whitespace, excluding < for the e-mail address
			Dim namePattern As String = "[^\s<](?:[^<]*[^\s<])?"
			Dim emailPattern As String = "<([^>]+)>"
			Dim attendeeRegex As Regex = New Regex(String.Format("^\s*({0})\s*(?:{1})?", namePattern, emailPattern))

			Dim attendees As List(Of Attendee) = New List(Of Attendee)()

			For Each attendeeString As String In attendeeStrings
				If String.IsNullOrEmpty(attendeeString) Then
					Continue For
				End If

				Dim match As Match = attendeeRegex.Match(attendeeString)
				Dim name As String = match.Groups(1).Value.Trim()
				Dim emailAddress As String = match.Groups(2).Value.Trim()

				If String.IsNullOrEmpty(name) Then
					Continue For
				End If

				If String.IsNullOrEmpty(emailAddress) Then
					emailAddress = name
				End If

				attendees.Add(New Attendee(name, emailAddress))
			Next attendeeString

			Return attendees
		End Function



		Private Sub PopulateAttendeesWithWinContacts()
			If ShowWinContactsAsAttendees AndAlso Not _calendarService Is Nothing Then
				AttendeesList.Clear()
				AttendeesList.AddRange(_calendarService.GetAllWindowsContactsAsAttendees())
			End If
		End Sub

		Private Sub ClearAttendees()
			AttendeesList.Clear()
		End Sub

		#End Region ' Private

		#End Region ' Methods
	End Class
End Namespace
